From ee9c67c31f773ba2ee5711901af739bb9ed813bd Mon Sep 17 00:00:00 2001 From: Alex Williamson Date: Thu, 20 Mar 2008 14:29:09 -0600 Subject: [PATCH] [IA64] New SIOEmu interface: pass callback data in memory. This fixes lost data for callback while hypercall case. Signed-off-by: Tristan Gingold --- xen/arch/ia64/asm-offsets.c | 2 + xen/arch/ia64/vmx/sioemu.c | 190 ++++++++++---------------- xen/arch/ia64/vmx/vmx_fault.c | 4 - xen/arch/ia64/vmx/vmx_init.c | 4 + xen/include/asm-ia64/sioemu.h | 2 - xen/include/asm-ia64/vmx_vpd.h | 8 +- xen/include/public/arch-ia64/sioemu.h | 33 +++-- 7 files changed, 107 insertions(+), 136 deletions(-) diff --git a/xen/arch/ia64/asm-offsets.c b/xen/arch/ia64/asm-offsets.c index aefad7fd2b..55678f0ce7 100644 --- a/xen/arch/ia64/asm-offsets.c +++ b/xen/arch/ia64/asm-offsets.c @@ -150,6 +150,8 @@ void foo(void) DEFINE(IA64_VCPU_OPCODE_OFFSET, offsetof (struct vcpu, arch.arch_vmx.opcode)); DEFINE(SWITCH_MPTA_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.mpta)); DEFINE(IA64_PT_REGS_R16_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f)); + DEFINE(IA64_PT_REGS_R2_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f)); + DEFINE(IA64_PT_REGS_R8_SLOT, (((offsetof(struct pt_regs, r16)-sizeof(struct pt_regs))>>3)&0x3f)); DEFINE(IA64_VCPU_FLAGS_OFFSET,offsetof(struct vcpu ,arch.arch_vmx.flags)); DEFINE(IA64_VCPU_MMU_MODE_OFFSET,offsetof(struct vcpu, arch.arch_vmx.mmu_mode)); diff --git a/xen/arch/ia64/vmx/sioemu.c b/xen/arch/ia64/vmx/sioemu.c index 6cabe82b37..dad0d414fa 100644 --- a/xen/arch/ia64/vmx/sioemu.c +++ b/xen/arch/ia64/vmx/sioemu.c @@ -26,171 +26,137 @@ #include #include -static void -sioemu_save_regs (VCPU *vcpu) -{ - REGS *regs = vcpu_regs(vcpu); - - vcpu->arch.arch_vmx.stub_saved[0] = regs->r16; - vcpu->arch.arch_vmx.stub_saved[1] = regs->r17; - vcpu->arch.arch_vmx.stub_saved[2] = regs->r18; - vcpu->arch.arch_vmx.stub_saved[3] = regs->r19; - vcpu->arch.arch_vmx.stub_saved[4] = regs->r20; - vcpu->arch.arch_vmx.stub_saved[5] = regs->r21; - vcpu->arch.arch_vmx.stub_saved[6] = regs->r22; - vcpu->arch.arch_vmx.stub_saved[7] = regs->r23; - vcpu->arch.arch_vmx.stub_saved[8] = regs->r24; - vcpu->arch.arch_vmx.stub_saved[9] = regs->r25; - vcpu->arch.arch_vmx.stub_saved[10] = regs->r26; - vcpu->arch.arch_vmx.stub_saved[11] = regs->r27; - vcpu->arch.arch_vmx.stub_saved[12] = regs->r28; - vcpu->arch.arch_vmx.stub_saved[13] = regs->r29; - vcpu->arch.arch_vmx.stub_saved[14] = regs->r30; - vcpu->arch.arch_vmx.stub_saved[15] = regs->r31; - vcpu->arch.arch_vmx.stub_nats = - (regs->eml_unat >> IA64_PT_REGS_R16_SLOT) & 0xffff; -} - -static void -sioemu_restore_regs (VCPU *vcpu) -{ - REGS *regs = vcpu_regs(vcpu); - - /* First restore registers. */ - regs->cr_iip = regs->r28; - regs->cr_ifs = regs->r30; - vmx_vcpu_set_psr (vcpu, regs->r29); - - regs->eml_unat &= ~(0xffffUL << IA64_PT_REGS_R16_SLOT); - regs->eml_unat |= vcpu->arch.arch_vmx.stub_nats << IA64_PT_REGS_R16_SLOT; - - regs->r16 = vcpu->arch.arch_vmx.stub_saved[0]; - regs->r17 = vcpu->arch.arch_vmx.stub_saved[1]; - regs->r18 = vcpu->arch.arch_vmx.stub_saved[2]; - regs->r19 = vcpu->arch.arch_vmx.stub_saved[3]; - regs->r20 = vcpu->arch.arch_vmx.stub_saved[4]; - regs->r21 = vcpu->arch.arch_vmx.stub_saved[5]; - regs->r22 = vcpu->arch.arch_vmx.stub_saved[6]; - regs->r23 = vcpu->arch.arch_vmx.stub_saved[7]; - regs->r24 = vcpu->arch.arch_vmx.stub_saved[8]; - regs->r25 = vcpu->arch.arch_vmx.stub_saved[9]; - regs->r26 = vcpu->arch.arch_vmx.stub_saved[10]; - regs->r27 = vcpu->arch.arch_vmx.stub_saved[11]; - regs->r28 = vcpu->arch.arch_vmx.stub_saved[12]; - regs->r29 = vcpu->arch.arch_vmx.stub_saved[13]; - regs->r30 = vcpu->arch.arch_vmx.stub_saved[14]; - regs->r31 = vcpu->arch.arch_vmx.stub_saved[15]; - -} - -static REGS * +struct sioemu_callback_info * sioemu_deliver (void) { VCPU *vcpu = current; REGS *regs = vcpu_regs(vcpu); + struct sioemu_callback_info *info = vcpu->arch.arch_vmx.sioemu_info_mva; unsigned long psr = vmx_vcpu_get_psr(vcpu); if (vcpu->vcpu_info->evtchn_upcall_mask) panic_domain (NULL, "sioemu_deliver: aleady in stub mode\n"); + if (info == NULL) + panic_domain (NULL, "sioemu_deliver: set_callback not called\n"); /* All cleared, but keep BN. */ vmx_vcpu_set_psr(vcpu, IA64_PSR_MC | (psr & IA64_PSR_BN)); - /* Save registers. */ - sioemu_save_regs (vcpu); - - /* Context. */ - regs->r28 = regs->cr_iip; - regs->r29 = psr; - regs->r30 = regs->cr_ifs; + /* Set info. */ + info->ip = regs->cr_iip; + info->psr = psr; + info->ifs = regs->cr_ifs; + info->nats = (((regs->eml_unat >> IA64_PT_REGS_R8_SLOT) & 0x0f) << 8) + | (((regs->eml_unat >> IA64_PT_REGS_R2_SLOT) & 1) << 2); + info->r8 = regs->r8; + info->r9 = regs->r9; + info->r10 = regs->r10; + info->r11 = regs->r11; + info->r2 = regs->r2; regs->cr_ifs = 0; // pre-cover - regs->cr_iip = vcpu->arch.event_callback_ip; - regs->eml_unat &= ~(0xffffUL << IA64_PT_REGS_R16_SLOT); - - /* Parameters. */ - regs->r16 = 0; - regs->r17 = vcpu->arch.arch_vmx.stub_buffer; + regs->eml_unat &= ~(1UL << IA64_PT_REGS_R8_SLOT); + regs->r8 = vcpu->arch.arch_vmx.sioemu_info_gpa; /* Mask events. */ vcpu->vcpu_info->evtchn_upcall_mask = 1; debugger_event(XEN_IA64_DEBUG_ON_EVENT); - return regs; + return info; } -void +static void sioemu_callback_return (void) { VCPU *vcpu = current; REGS *regs = vcpu_regs(vcpu); - u64 cmd = regs->r16; - u64 arg1 = regs->r19; - u64 arg2 = regs->r20; - u64 arg3 = regs->r21; + struct sioemu_callback_info *info = vcpu->arch.arch_vmx.sioemu_info_mva; - if ((cmd & ~0x1UL) != 0) + if (info == NULL) + panic_domain (NULL, "sioemu_deliver: set_callback not called\n"); + if ((info->cause & ~0x1UL) != 0) panic_domain (NULL, "sioemu_callback_return: bad operation (%lx)\n", - cmd); + info->cause); /* First restore registers. */ - regs->cr_iip = regs->r28; - regs->cr_ifs = regs->r30; - vmx_vcpu_set_psr (vcpu, regs->r29); - - sioemu_restore_regs (vcpu); + regs->cr_iip = info->ip; + regs->cr_ifs = info->ifs; + vmx_vcpu_set_psr (vcpu, info->psr); + regs->r8 = info->r8; + regs->r9 = info->r9; + regs->r10 = info->r10; + regs->r11 = info->r11; + regs->r2 = info->r2; + regs->eml_unat &= ~((0x0fUL << IA64_PT_REGS_R8_SLOT) + | (1UL << IA64_PT_REGS_R2_SLOT)); + regs->eml_unat |= (((info->nats >> 8) & 0x0f) << IA64_PT_REGS_R8_SLOT) + | (((info->nats >> 2) & 1) << IA64_PT_REGS_R2_SLOT); /* Unmask events. */ vcpu->vcpu_info->evtchn_upcall_mask = 0; /* Then apply commands. */ - if (cmd & 1) { - emulate_io_update (vcpu, arg1, arg2, arg3); + if (info->cause & 1) { + emulate_io_update (vcpu, info->arg0, info->arg1, info->arg2); } } void sioemu_deliver_event (void) { - REGS *regs; + struct sioemu_callback_info *info; - regs = sioemu_deliver (); - regs->r16 = SIOEMU_CB_EVENT; + info = sioemu_deliver (); + info->cause = SIOEMU_CB_EVENT; } void sioemu_io_emulate (unsigned long padr, unsigned long data, unsigned long data1, unsigned long word) { - REGS *regs; - - regs = sioemu_deliver (); - regs->r16 = SIOEMU_CB_IO_EMULATE; - regs->r19 = padr; - regs->r20 = data; - regs->r21 = data1; - regs->r22 = word; + struct sioemu_callback_info *info; + + info = sioemu_deliver (); + info->cause = SIOEMU_CB_IO_EMULATE; + info->arg0 = padr; + info->arg1 = data; + info->arg2 = data1; + info->arg3 = word; } void -sioemu_wakeup_vcpu (int vcpu_id) +sioemu_sal_assist (struct vcpu *v) { - REGS *regs; + struct sioemu_callback_info *info; - regs = sioemu_deliver(); - regs->r16 = SIOEMU_CB_WAKEUP_VCPU; - regs->r19 = vcpu_id; + info = sioemu_deliver (); + info->cause = SIOEMU_CB_SAL_ASSIST; } -void -sioemu_sal_assist (struct vcpu *v) +static int +sioemu_set_callback (struct vcpu *v, unsigned long cb_ip, unsigned long paddr) { - REGS *regs; + struct page_info *page; + unsigned long mfn; + pte_t pte; + + v->arch.event_callback_ip = cb_ip; + if ((paddr & 0xfff) || v->arch.arch_vmx.sioemu_info_mva) + return -EINVAL; + pte = *lookup_noalloc_domain_pte(v->domain, paddr); + if (!pte_present(pte) || !pte_mem(pte)) + return -EINVAL; + mfn = (pte_val(pte) & _PFN_MASK) >> PAGE_SHIFT; + ASSERT(mfn_valid(mfn)); - regs = sioemu_deliver(); - regs->r16 = SIOEMU_CB_SAL_ASSIST; + page = mfn_to_page(mfn); + if (get_page(page, v->domain) == 0) + return -EINVAL; + v->arch.arch_vmx.sioemu_info_gpa = paddr; + v->arch.arch_vmx.sioemu_info_mva = mfn_to_virt(mfn); + return 0; } static int @@ -234,8 +200,7 @@ sioemu_hypercall (struct pt_regs *regs) switch (regs->r2 & FW_HYPERCALL_NUM_MASK_LOW) { case SIOEMU_HYPERCALL_SET_CALLBACK: - current->arch.event_callback_ip = regs->r8; - current->arch.arch_vmx.stub_buffer = regs->r9; + regs->r8 = sioemu_set_callback(current, regs->r8, regs->r9); break; case SIOEMU_HYPERCALL_START_FW: regs->cr_iip = regs->r8; @@ -254,12 +219,6 @@ sioemu_hypercall (struct pt_regs *regs) regs->r9 = now; break; } - case SIOEMU_HYPERCALL_GET_REGS: - sioemu_restore_regs(current); - break; - case SIOEMU_HYPERCALL_SET_REGS: - sioemu_save_regs(current); - break; case SIOEMU_HYPERCALL_FLUSH_CACHE: regs->r8 = ia64_sal_cache_flush(regs->r8); break; @@ -271,7 +230,6 @@ sioemu_hypercall (struct pt_regs *regs) regs->r8, regs->r9, regs->r10); break; case SIOEMU_HYPERCALL_CALLBACK_RETURN: - regs->r2 = regs->r27; sioemu_callback_return (); vcpu_decrement_iip(current); break; diff --git a/xen/arch/ia64/vmx/vmx_fault.c b/xen/arch/ia64/vmx/vmx_fault.c index b4af2bc21b..efd874926e 100644 --- a/xen/arch/ia64/vmx/vmx_fault.c +++ b/xen/arch/ia64/vmx/vmx_fault.c @@ -215,10 +215,6 @@ vmx_ia64_handle_break (unsigned long ifa, struct pt_regs *regs, unsigned long is vcpu_increment_iip(v); } return IA64_NO_FAULT; - } else if (d->arch.is_sioemu - && iim == SIOEMU_HYPERPRIVOP_CALLBACK_RETURN) { - sioemu_callback_return (); - return IA64_NO_FAULT; } } vmx_reflect_interruption(ifa, isr, iim, 11, regs); diff --git a/xen/arch/ia64/vmx/vmx_init.c b/xen/arch/ia64/vmx/vmx_init.c index 1a5b46da26..955d29bdd2 100644 --- a/xen/arch/ia64/vmx/vmx_init.c +++ b/xen/arch/ia64/vmx/vmx_init.c @@ -540,6 +540,10 @@ vmx_relinquish_vcpu_resources(struct vcpu *v) kill_timer(&vtm->vtm_timer); + if (v->arch.arch_vmx.sioemu_info_mva) + put_page(virt_to_page((unsigned long) + v->arch.arch_vmx.sioemu_info_mva)); + free_domain_tlb(v); free_vpd(v); } diff --git a/xen/include/asm-ia64/sioemu.h b/xen/include/asm-ia64/sioemu.h index 55988dc1ae..38ed407e90 100644 --- a/xen/include/asm-ia64/sioemu.h +++ b/xen/include/asm-ia64/sioemu.h @@ -23,9 +23,7 @@ #define __ASM_SIOEMU_H_ extern void sioemu_hypercall (struct pt_regs *regs); extern void sioemu_deliver_event (void); -extern void sioemu_callback_return (void); extern void sioemu_io_emulate (unsigned long padr, unsigned long data, unsigned long data1, unsigned long word); -extern void sioemu_wakeup_vcpu (int vcpu_id); extern void sioemu_sal_assist (struct vcpu *v); #endif /* __ASM_SIOEMU_H_ */ diff --git a/xen/include/asm-ia64/vmx_vpd.h b/xen/include/asm-ia64/vmx_vpd.h index cdf36e086e..324cae598d 100644 --- a/xen/include/asm-ia64/vmx_vpd.h +++ b/xen/include/asm-ia64/vmx_vpd.h @@ -40,6 +40,8 @@ #include #include +struct sioemu_callback_info; + #define VPD_SHIFT 16 #define VPD_SIZE (1 << VPD_SHIFT) @@ -74,9 +76,9 @@ struct arch_vmx_struct { unsigned long ivt_current; struct ivt_debug ivt_debug[IVT_DEBUG_MAX]; #endif - unsigned long stub_saved[16]; - unsigned long stub_buffer; - unsigned int stub_nats; + /* sioemu info buffer. */ + unsigned long sioemu_info_gpa; + struct sioemu_callback_info *sioemu_info_mva; }; #define VMX_DOMAIN(v) v->arch.arch_vmx.flags diff --git a/xen/include/public/arch-ia64/sioemu.h b/xen/include/public/arch-ia64/sioemu.h index a98af6a487..c04ab836c8 100644 --- a/xen/include/public/arch-ia64/sioemu.h +++ b/xen/include/public/arch-ia64/sioemu.h @@ -38,10 +38,6 @@ /* Get wallclock time. */ #define SIOEMU_HYPERCALL_GET_TIME 0x04 -/* Get/Set shadow registers. */ -#define SIOEMU_HYPERCALL_GET_REGS 0x05 -#define SIOEMU_HYPERCALL_SET_REGS 0x06 - /* Flush cache. */ #define SIOEMU_HYPERCALL_FLUSH_CACHE 0x07 @@ -68,11 +64,26 @@ /* A SAL hypercall is executed. */ #define SIOEMU_CB_SAL_ASSIST 0x03 - -/* SIOEMU firmware mode hypercalls. */ - -/* Return from callback. r16=0. - Unmask vcpu events. */ -#define SIOEMU_HYPERPRIVOP_CALLBACK_RETURN 0x01 - +#ifndef __ASSEMBLY__ +struct sioemu_callback_info { + /* Saved registers. */ + unsigned long ip; + unsigned long psr; + unsigned long ifs; + unsigned long nats; + unsigned long r8; + unsigned long r9; + unsigned long r10; + unsigned long r11; + + /* Callback parameters. */ + unsigned long cause; + unsigned long arg0; + unsigned long arg1; + unsigned long arg2; + unsigned long arg3; + unsigned long _pad2[2]; + unsigned long r2; +}; +#endif /* __ASSEMBLY__ */ #endif /* __XEN_PUBLIC_IA64_SIOEMU_H__ */ -- 2.30.2